package com.dada.controller;

import com.dada.domain.common.JsonResult;
import com.dada.domain.exception.ApiException;
import com.dada.domain.exception.ServiceException;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import static com.dada.domain.common.Code.*;
import static java.lang.String.format;
import static javax.servlet.http.HttpServletResponse.*;
import static org.springframework.http.HttpHeaders.CACHE_CONTROL;

@Slf4j
@ControllerAdvice
public class GlobalController {

    private static final String NO_STORE = "no-store";

    /**
     * 捕获所有异常
     */
    @ExceptionHandler(Throwable.class)
    @ResponseBody
    public JsonResult handleAllException(HttpServletRequest request, HttpServletResponse response, Throwable e) {
        return this._handleException(request, response, e);
    }

    /*======================================= 私有方法 =======================================*/

    /**
     * 处理异常的响应
     */
    private JsonResult _handleException(HttpServletRequest request, HttpServletResponse response, Throwable error) {
        response.setHeader(CACHE_CONTROL, NO_STORE);

        // 获取异常源
        while (error.getCause() != null) {
            if (error instanceof ServiceException && !(error.getCause() instanceof ServiceException)) {
                break;
            }
            if (error instanceof ApiException && !(error.getCause() instanceof ApiException)) {
                break;
            }
            error = error.getCause();
        }


        String errorMsg = error.getMessage();
        log.debug("Exception occurred: " + errorMsg + ". [URL=" + request.getRequestURI() + "]", error);

        if (error instanceof ApiException) {
            // API错误
            int code = ((ApiException) error).getCode();
            if (code == BASE_BAD_PARAMS.getCode()) {
                response.setStatus(SC_BAD_REQUEST);
            } else if (code == SERVER_ERROR.getCode()) {
                response.setStatus(SC_INTERNAL_SERVER_ERROR);
            } else if (code == BASE_NOT_FOUND.getCode()) {
                response.setStatus(SC_NOT_FOUND);
            } else if (code == BASE_FORBIDDEN.getCode()) {
                response.setStatus(SC_FORBIDDEN);
            }
            return JsonResult.error(code, errorMsg);
        } else if (error instanceof IllegalArgumentException) {
            // 一般是Assert异常
            response.setStatus(SC_BAD_REQUEST);
            return JsonResult.error(SERVER_ERROR);
        } else if (error instanceof MethodArgumentNotValidException) {
            // 捕获validation规范的数据验证异常
            MethodArgumentNotValidException ex = (MethodArgumentNotValidException) error;
            FieldError fieldError = ex.getBindingResult().getFieldError();
            if (StringUtils.isNotBlank(fieldError.getDefaultMessage())) {
                return JsonResult.error(BASE_BAD_PARAMS.getCode(), format("%s: %s", fieldError.getField(), fieldError.getDefaultMessage()));
            } else {
                return JsonResult.error(BASE_BAD_PARAMS);
            }
        } else {
            // 其他异常都返回「服务器异常」错误
            return JsonResult.error(errorMsg);
        }
    }
}